﻿/*************************************************************************************
 *
 * 文 件 名：  Worker
 * 描    述：  资源配置初始化服务
 * 
 * 版    本：  V1.0
 * 创 建 者：  YSW
 * 创建时间：  2021-10-19 9:40:05
 * ======================================
 * 历史更新记录
 * 版本：V          修改时间：         修改人：
 * 修改内容：
 * ======================================
*************************************************************************************/

using CommonModel.Util;
using GXRTBTC.DataStorageService.Model;
using GXRTBTC.PublicClassLibrary;
using GXRTBTC.PublicClassLibrary.Field;
using GXRTBTC.PublicClassLibrary.Model;
using GXRTBTC.PublicClassLibrary.Redis;
using GXRTBTC.PublicClassLibrary.Util;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NewLife;
using Newtonsoft.Json;
using Npgsql;
using PtlSvr.CfgLoader;
using RedisHelp;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

namespace GXRTBTC.ResourceInitService
{
    /// <summary>
    /// 后台服务
    /// </summary>
    public class Worker : BackgroundService
    {
        #region 参数
        /// <summary>
        /// 日志
        /// </summary>
        private readonly ILogger mLogger;
        /// <summary>
        /// 配置
        /// </summary>
        private readonly IConfiguration mConfiguration;
        /// <summary>
        /// StackExchange.Redis
        /// </summary>
        private RedisHelper redis { get; set; }

        /// <summary>
        /// 数据库连接
        /// </summary>
        private DbConnection dbConnection { get; set; }
        //private DbConnection dbConnectionSql { get; set; }

        private Dictionary<string, List<string>> stationPositionids { get; set; } = new Dictionary<string, List<string>>();
        private Dictionary<string, string> subTablesCache { get; set; } = new();
        /// <summary>
        /// 所有工位号
        /// </summary>
        private Dictionary<string, string> positionids { get; set; } = new();
        /// <summary>
        /// 对象锁，用于线程间同步gapNums
        /// </summary>
        private Object syncLock { get; } = new object();
        /// <summary>
        /// 数据库是否连接
        /// </summary>
        private bool IsDbConn { get; set; } = false;
        /// <summary>
        /// sqlserver数据库
        /// 针对1.0监控服务数据库
        /// </summary>
        private bool IsDbConnSql { get; set; } = false;

        /// <summary>
        /// 配置集
        /// </summary>
        private Dictionary<string, string> paramInfo { get; set; } = new();
        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="configuration"></param>
        public Worker(ILogger<Worker> logger, IConfiguration configuration)
        {
            this.mLogger = logger;
            this.mConfiguration = configuration;

            mLogger.LogInformation("host=" + TransForm.GetHostIPOrName());

            //给通用日志赋值
            CommonUtil.mLogger = logger;
            mLogger.LogInformation("初始化 ...");
            Init();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        private void Init()
        {
            try
            {
                //redis初始化
                string redisConnString = "";

#if DEBUG
                redisConnString = RsaEncrypt.DecryptFree(mConfiguration["RedisConnStringDebug"]);
#else
                
                redisConnString = RsaEncrypt.DecryptFree(mConfiguration["RedisConnString"]);
#endif

                mLogger.LogInformation("RedisConnString=" + redisConnString);
                redis = new RedisHelper(redisConnString, mLogger);
            }
            catch (Exception e)
            {
                mLogger.LogError("redis连接异常，" + e);
            }

            //初始化数据库
            InitDb();
            //sqlserver
            InitDbSql();

            InitCacheInfo();

            //数据库连接正常，则读取其它配置
            if (IsDbConn)
            {
                paramInfo = DbUtil.GetParamInfo(dbConnection);
            }
        }

        /// <summary>
        /// 初始化信息
        /// </summary>
        private void TimerInit()
        {
            Thread.Sleep(60 * 1000);
            while (true)
            {
                InitCacheInfo();
                Thread.Sleep(60 * 1000);
            }
        }

        /// <summary>
        /// redis缓存信息初始化
        /// </summary>
        private void InitCacheInfo()
        {
            try
            {
                lock (syncLock)
                {
                    List<string> tmpPositionids = redis.HashKeys<string>("station_deviceInfos");
                    if (tmpPositionids != null && tmpPositionids.Count > 0)
                    {
                        positionids = tmpPositionids.ToDictionary(l => l, l => "");
                    }
                }

                lock (syncLock)
                {
                    Dictionary<string, List<string>> tmpStationPositionids = redis.HashGetAllDict<List<string>>("station_cfg_positions");
                    stationPositionids = (tmpStationPositionids != null && tmpStationPositionids.Count > 0) ? tmpStationPositionids : stationPositionids;
                }

                lock (syncLock)
                {
                    Dictionary<string, string> tmpSubTablesCache = redis.HashGetAllDict<string>("alarmHisSubTables");
                    subTablesCache = (tmpSubTablesCache != null && tmpSubTablesCache.Count > 0) ? tmpSubTablesCache : subTablesCache;
                }

            }
            catch (Exception e)
            {
                mLogger.LogInformation("更新获取台站信息缓存失败，" + e);
            }
        }

        /// <summary>
        /// 数据库连接初始化
        /// </summary>
        private void InitDb()
        {
            try
            {
                //添加解密
                dbConnection = new NpgsqlConnection(RsaEncrypt.DecryptFree(mConfiguration["PgSQLConnString"]));
                dbConnection.Open();
                IsDbConn = true;
                mLogger.LogInformation("pgSQL数据库连接成功！");
            }
            catch (Exception e)
            {
                IsDbConn = false;
                mLogger.LogError("数据库连接失败！" + e.Message);
            }
        }

        /// <summary>
        /// sqlserver数据库连接
        /// </summary>
        private void InitDbSql()
        {
            //try
            //{
            //    string SqlServerConnString21 = paramInfo.GetValueOrDefault("SqlServerConnString21", "Data Source=10.170.1.21;Initial Catalog=MOOS;Integrated Security=false;Pwd=Net490312;User ID=sa");
            //    dbConnectionSql = new SqlConnection(SqlServerConnString21);
            //    dbConnectionSql.Open();
            //    IsDbConnSql = true;
            //    mLogger.LogInformation("sqlserver数据库连接成功！");
            //}
            //catch (Exception e)
            //{
            //    IsDbConnSql = false;
            //    mLogger.LogError("sqlserver数据库连接失败！" + e.Message);
            //}
        }

        /// <summary>
        /// 判断数据库连接
        /// </summary>
        private void CheckDbState()
        {
            try
            {
                DbUtil.ExecReader(dbConnection, "select now() datetime", false);
                if (dbConnection.State != ConnectionState.Open)
                {
                    dbConnection.Open();
                }
                //else
                //{
                //    dbConnection.Close();
                //    dbConnection.Open();
                //}
                IsDbConn = true;
            }
            catch (Exception e)
            {
                IsDbConn = false;
                mLogger.LogError("数据库连接失败！" + e.Message);
            }
        }

        private void CheckDbStateSql()
        {
            //try
            //{
            //    DbUtil.ExecReader(dbConnectionSql, "select getdate() datetime", false);
            //    if (dbConnection.State != ConnectionState.Open)
            //    {
            //        dbConnection.Open();
            //    }
            //    //else
            //    //{
            //    //    dbConnection.Close();
            //    //    dbConnection.Open();
            //    //}
            //    IsDbConnSql = true;
            //}
            //catch (Exception e)
            //{
            //    IsDbConnSql = false;
            //    mLogger.LogError("sqlserver数据库连接失败！" + e.Message);
            //}
        }

        /// <summary>
        /// 数据处理
        /// </summary>
        private void DealData()
        {
            while (true)
            {
                mLogger.LogInformation("更新配置开始 ...");
                try
                {
                    dbConnection.Close();
                }
                catch { }

                CheckDbState();
                CheckDbStateSql();

                try
                {
                    if (IsDbConn)
                    {
#if DEBUG
                        //DbUtil.ExecSql(dbConnection, "update position_id_match set dev_port = replace(dev_port, '50', '5') where dev_port like '50%'");
#endif

                        IBatch batch = redis.CreateBatch();

                        //初始化台站信息
                        Dictionary<string, Dictionary<string, Dictionary<string, string>>> stations = DbUtil.GetAllStation(dbConnection);
                        string stationIdGlobal = "9999";
                        if (stations != null && stations.Count > 0)
                        {
                            Dictionary<string, Dictionary<string, string>> stationsInfo = stations["stationIds"];
                            stationIdGlobal = stations["stationIds"].Keys.ToList()[0];
                            redis.StringSet("stations", stations["stationIds"]);   //台站批量写入redis
                            redis.StringSet("stationAddrs", stations["stationAddrs"]);   //台站批量写入redis
                            redis.StringSet("stationNames", stations["stationNames"]);   //台站批量写入redis
                            //IBatch batchAddr = redis.CreateBatch();
                            foreach (string ipAddr in stations["stationAddrs"].Keys)
                            {
                                batch.MHashSetAsync("ipaddr_station", ipAddr, stations["stationAddrs"][ipAddr]["station_id"]);
                            }
                            batch.Execute();
                        }
                        mLogger.LogInformation("更新台站信息");

                        /************************默认配置项增加******************************************************************/
                        string paramSql = $"insert into param_info(id, param_name, param_value, memo) select (select max(id)+1 from param_info), 'stationIdGlobal', '{stationIdGlobal}', '台站自身编码，全局变量' where not exists(select 1 from param_info where param_name = 'stationIdGlobal')";
                        DbUtil.ExecSql(dbConnection, paramSql);
                        paramSql = $"update param_info set param_value='{stationIdGlobal}' where param_name='stationIdGlobal'";
                        DbUtil.ExecSql(dbConnection, paramSql);
                        /************************默认配置项增加******************************************************************/

                        /************************配置参数写入缓存******************************************************************/
                        paramInfo = DbUtil.GetParamInfo(dbConnection);
                        if (paramInfo != null && paramInfo.Count > 0)
                        {
                            foreach (string paramKey in paramInfo.Keys)
                            {
                                redis.HashSet("paramInfo", paramKey, paramInfo[paramKey]);
                            }

                            Dictionary<string, string> tmpParamInfo = redis.HashGetAllDict<string>("paramInfo");
                            foreach (string paramKey in tmpParamInfo.Keys)
                            {
                                if (!paramInfo.ContainsKey(paramKey))
                                {
                                    redis.HashDelete("paramInfo", paramKey);
                                }
                            }

                            //写全局台站编号
                            if (paramInfo.ContainsKey("stationIdGlobal"))
                            {
                                redis.StringSet("station_id", paramInfo["stationIdGlobal"]);
                            }
                        }
                        mLogger.LogInformation("配置参数写入缓存");
                        /************************配置参数写入缓存******************************************************************/

                        /************************更新数据模型******************************************************************/

                        //台站子系统
                        Dictionary<string, Dictionary<string, string>> stationSubSystemMatch = DbUtil.GetStationSubSystemMatch(dbConnection);
                        if (stationSubSystemMatch != null && stationSubSystemMatch.Count > 0)
                        {
                            redis.StringSet("stationSubSystemMatch", stationSubSystemMatch);
                        }
                        mLogger.LogInformation("更新台站子系统");

                        Dictionary<string, Dictionary<string, Dictionary<string, string>>> frqAndProgram = DbUtil.GetFrqAndProgram(dbConnection);
                        if (frqAndProgram != null && frqAndProgram.Count > 0)
                        {
                            redis.StringSet("stationFrqAndProgram", frqAndProgram);
                        }
                        mLogger.LogInformation("更新台站频率匹配节目数据");

                        /************************前置配置文件******************************************************************/
                        Dictionary<int, TableInfo> tableInfos = DbUtil.initSchemaMapFromDb(dbConnection);
                        if (tableInfos != null && tableInfos.Count > 0)
                        {
                            foreach (int tbId in tableInfos.Keys)
                            {
                                redis.HashSet("pre_save_tableInfo", tbId.ToString(), tableInfos[tbId]);
                            }
                            //移除无用的key
                            List<string> existsKeys = redis.HashKeys<string>("pre_save_tableInfo");
                            List<string> delKeys = existsKeys.Where(l => !tableInfos.ContainsKey(int.Parse(l))).ToList();
                            foreach (string key in delKeys)
                            {
                                redis.HashDelete("pre_save_tableInfo", key);
                            }
                        }
                        mLogger.LogInformation("更新前置配置结构");

                        Dictionary<string, SchemaDocument> schemaDict = SchemaServer.InitSchemaMapFromDb(dbConnection);
                        if (schemaDict != null && schemaDict.Count > 0)
                        {
                            foreach (string key in schemaDict.Keys)
                            {
                                string val = JsonConvert.SerializeObject(schemaDict[key]);
                                redis.HashSet("pre_analysis_config", key, val);
                            }
                            //移除无用的key
                            List<string> existsKeys = redis.HashKeys<string>("pre_analysis_config");
                            List<string> delKeys = existsKeys.Where(l => l == null || "".Equals(l) || !schemaDict.ContainsKey(l)).ToList();
                            foreach (string key in delKeys)
                            {
                                redis.HashDelete("pre_analysis_config", key ?? "");
                            }
                        }
                        mLogger.LogInformation("更新前置配置明细");
                        /************************前置配置文件******************************************************************/

                        /************************获取海康威视通道状态******************************************************************/
                        Dictionary<string, List<Dictionary<string, string>>> stationHIKRecs = DbUtil.GetStationHIKRec(dbConnection);
                        if (stationHIKRecs != null && stationHIKRecs.Count > 0)
                        {
                            foreach (string stationId in stationHIKRecs.Keys)
                            {
                                batch.MHashSetAsync("stationHIKRec", stationId, JsonConvert.SerializeObject(stationHIKRecs[stationId]));
                            }

                            batch.Execute();
                        }
                        mLogger.LogInformation("获取获取海康威视通道信息数据");
                        /************************获取海康威视通道状态******************************************************************/

                        /************************更新总览模型******************************************************************/
                        //模型结构 总览数据用
                        Dictionary<string, Dictionary<string, Dictionary<string, Object>>> nodeModelAllNew = DbUtil.GetStationBasicNodeModel(dbConnection);
                        if (nodeModelAllNew != null)
                        {
                            //树结构
                            if (nodeModelAllNew.ContainsKey("nodeModelBasic") && nodeModelAllNew["nodeModelBasic"].Count > 0)
                            {
                                foreach (string staId in nodeModelAllNew["nodeModelBasic"].Keys)
                                {
                                    redis.HashSet<Dictionary<string, Object>>("stationNodeModelBasic", staId, nodeModelAllNew["nodeModelBasic"][staId]);
                                }

                                //移除无用的key
                                List<string> existsKeys = redis.HashKeys<string>("stationNodeModelBasic");
                                List<string> delKeys = existsKeys.Where(l => !nodeModelAllNew["nodeModelBasic"].ContainsKey(l)).ToList();
                                foreach (string key in delKeys)
                                {
                                    redis.HashDelete("stationNodeModelBasic", key);
                                }
                            }
                            if (nodeModelAllNew.ContainsKey("nodeModelIdx") && nodeModelAllNew["nodeModelIdx"].Count > 0)
                            {
                                foreach (string staId in nodeModelAllNew["nodeModelIdx"].Keys)
                                {
                                    //台站模型，新增清除功能，在发现新模型和旧模型的数据有不一致时，清空缓存的总览镜像
                                    string tmpModel = redis.HashGet("stationNodeModelIdx", staId);
                                    bool equ = (tmpModel == null || "".Equals(tmpModel)) ? false : tmpModel.Equals(JsonConvert.SerializeObject(nodeModelAllNew["nodeModelIdx"][staId]));
                                    if (tmpModel != null && !"".Equals(tmpModel) && !equ)
                                    {
                                        redis.KeyDelete(staId + "_overViewImage");
                                    }
                                    //不一样才写入
                                    if (!equ)
                                    {
                                        redis.HashSet<Dictionary<string, Object>>("stationNodeModelIdx", staId, nodeModelAllNew["nodeModelIdx"][staId]);
                                    }
                                }

                                //移除无用的key
                                List<string> existsKeys = redis.HashKeys<string>("stationNodeModelIdx");
                                List<string> delKeys = existsKeys.Where(l => !nodeModelAllNew["nodeModelIdx"].ContainsKey(l)).ToList();
                                foreach (string key in delKeys)
                                {
                                    redis.HashDelete("stationNodeModelIdx", key);
                                }
                            }
                        }
                        mLogger.LogInformation("更新总览模型");

                        //属性单独初始化
                        Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> nodeModel = DbUtil.GetNodeModel(dbConnection);
                        if (nodeModel != null && nodeModel.Count > 0)
                        {
                            //判断模型是否有变化，有变化则清空缓存的总览镜像
                            bool change = false;
                            foreach (string modelType in nodeModel.Keys)
                            {
                                foreach (string modelId in nodeModel[modelType].Keys)
                                {
                                    //台站模型，新增清除功能，在发现新模型和旧模型的数据有不一致时，清空缓存的总览镜像
                                    string tmpModel = redis.HashGet(modelType, modelId);
                                    bool equ = (tmpModel == null || "".Equals(tmpModel)) ? false : tmpModel.Equals(JsonConvert.SerializeObject(nodeModel[modelType][modelId]));
                                    if (tmpModel != null && !"".Equals(tmpModel) && !equ)
                                    {
                                        change = true;
                                    }
                                    if (!equ)
                                    {
                                        redis.HashSet(modelType, modelId, nodeModel[modelType][modelId]);
                                    }
                                }

                                //移除无用的key
                                if (nodeModel[modelType].Count > 0)
                                {
                                    List<string> existsKeys = redis.HashKeys<string>(modelType);
                                    List<string> delKeys = existsKeys.Where(l => !nodeModel[modelType].ContainsKey(l)).ToList();
                                    foreach (string key in delKeys)
                                    {
                                        redis.HashDelete(modelType, key);
                                    }
                                }
                            }

                            //如果有变化
                            if (change && stations != null && stations.ContainsKey("stationIds") && stations["stationIds"].Count > 0)
                            {
                                //台站模型，新增清除功能，在发现新模型和旧模型的数据有不一致时，清空缓存的总览镜像
                                foreach (string stationId in stations["stationIds"].Keys)
                                {
                                    redis.KeyDelete(stationId + "_overViewImage");
                                }
                            }
                        }
                        mLogger.LogInformation("更新总览属性");
                        /************************更新总览模型******************************************************************/

                        /************************更新操作/设置模型******************************************************************/
                        //操作具体属性已经在GetNodeModel那里初始化了
                        Dictionary<string, List<Dictionary<string, string>>> operateNewInfo = DbUtil.GetOperateAndSetModelInfo(dbConnection);
                        if (operateNewInfo != null && operateNewInfo.Count > 0)
                        {
                            //IBatch batchOperateNewInfo = redis.CreateBatch();
                            foreach (string key in operateNewInfo.Keys)
                            {
                                //redis.HashSet("operateParaModelNew", key, operateNewInfo[key]);
                                batch.MHashSetAsync("operateParaModelNew", key, JsonConvert.SerializeObject(operateNewInfo[key]));
                            }

                            //移除无用的key
                            List<string> existsKeys = redis.HashKeys<string>("operateParaModelNew");
                            List<string> delKeys = existsKeys.Where(l => !operateNewInfo.ContainsKey(l)).ToList();
                            foreach (string key in delKeys)
                            {
                                //redis.HashDelete("operateParaModelNew", key);
                                batch.MHashDeleteAsync("operateParaModelNew", key);
                            }
                            batch.Execute();
                        }
                        /************************更新操作/设置模型******************************************************************/

                        /************************更新告警模型******************************************************************/
                        //新结构
                        Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>> realAlarmModelInfo = DbUtil.GetAlarmModelInfo(dbConnection);
                        if (realAlarmModelInfo != null && realAlarmModelInfo.Count > 0)
                        {
                            foreach (string staId in realAlarmModelInfo.Keys)
                            {
                                redis.HashSet("stationAlarmNodeModel", staId, realAlarmModelInfo[staId]);
                            }
                            //移除无用的key
                            List<string> existsKeys = redis.HashKeys<string>("stationAlarmNodeModel");
                            List<string> delKeys = existsKeys.Where(l => !realAlarmModelInfo.ContainsKey(l)).ToList();
                            foreach (string key in delKeys)
                            {
                                redis.HashDelete("stationAlarmNodeModel", key);
                            }

                            //所有系统配置的工位号保存，station_deviceInfos信息里，只存在有数据上报的工位，这里也保存一份，相互补全
                            foreach (string staId in realAlarmModelInfo.Keys)
                            {
                                redis.HashSet("station_cfg_positions", staId, realAlarmModelInfo[staId].Keys);
                            }
                            //移除无用的key
                            existsKeys = redis.HashKeys<string>("station_cfg_positions");
                            delKeys = existsKeys.Where(l => !realAlarmModelInfo.ContainsKey(l)).ToList();
                            foreach (string key in delKeys)
                            {
                                redis.HashDelete("station_cfg_positions", key);
                            }
                        }

                        //告警字段模板
                        Dictionary<string, Dictionary<string, Dictionary<string, string>>> alarmModel = DbUtil.GetAlarmModel(dbConnection);
                        if (alarmModel != null && alarmModel.Count > 0)
                        {
                            foreach (string modelId in alarmModel.Keys)
                            {
                                redis.HashSet("stationAlarmDataModel", modelId, alarmModel[modelId]);
                            }
                            //移除无用的key
                            List<string> existsKeys = redis.HashKeys<string>("stationAlarmDataModel");
                            List<string> delKeys = existsKeys.Where(l => !alarmModel.ContainsKey(l)).ToList();
                            foreach (string key in delKeys)
                            {
                                redis.HashDelete("stationAlarmDataModel", key);
                            }
                        }
                        mLogger.LogInformation("更新告警模型");

                        //更新关联、衍生告警告警模型
                        List<Dictionary<string, Object>> relationAlarmInfos = DbUtil.GetRelationAlarmInfo(dbConnection);
                        if (relationAlarmInfos != null && relationAlarmInfos.Count > 0)
                        {
                            redis.StringSet("relationAlarmInfos", relationAlarmInfos);
                        }
                        mLogger.LogInformation("更新关联、衍生告警告警模型");
                        /************************更新告警模型******************************************************************/

                        /************************命令、模板相关******************************************************************/
                        Dictionary<string, Dictionary<string, string>> issuePara = DbUtil.GetIssuePara(dbConnection);
                        if (issuePara != null && issuePara.Count > 0)
                        {
                            foreach (string issueId in issuePara.Keys)
                            {
                                redis.HashSet("issueparas", issueId, issuePara[issueId]);
                            }
                            //移除无用的key
                            List<string> existsKeys = redis.HashKeys<string>("issueparas");
                            List<string> delKeys = existsKeys.Where(l => !issuePara.ContainsKey(l)).ToList();
                            foreach (string key in delKeys)
                            {
                                redis.HashDelete("issueparas", key);
                            }
                        }
                        mLogger.LogInformation("更新命令参数明细");

                        Dictionary<string, Dictionary<string, string>> issueTemplates = DbUtil.GetIssueTemplate(dbConnection);
                        if (issueTemplates != null && issueTemplates.Count > 0)
                        {
                            foreach (string templateId in issueTemplates.Keys)
                            {
                                redis.HashSet("issueTemplates", templateId, issueTemplates[templateId]);
                            }

                            //移除无用的key
                            List<string> existsKeys = redis.HashKeys<string>("issueTemplates");
                            List<string> delKeys = existsKeys.Where(l => !issueTemplates.ContainsKey(l)).ToList();
                            foreach (string key in delKeys)
                            {
                                redis.HashDelete("issueTemplates", key);
                            }
                        }
                        mLogger.LogInformation("获取命令模板信息");

                        Dictionary<string, Dictionary<string, Dictionary<string, string>>> devIssueInfo = DbUtil.GetDevIssueInfo(dbConnection);
                        if (devIssueInfo != null && devIssueInfo.Count > 0)
                        {
                            foreach (string device_type in devIssueInfo.Keys)
                            {
                                redis.HashSet("devIssueInfo", device_type, devIssueInfo[device_type]);
                            }
                            //移除无用的key
                            List<string> existsKeys = redis.HashKeys<string>("devIssueInfo");
                            List<string> delKeys = existsKeys.Where(l => !devIssueInfo.ContainsKey(l)).ToList();
                            foreach (string key in delKeys)
                            {
                                redis.HashDelete("devIssueInfo", key);
                            }
                        }
                        mLogger.LogInformation("更新设备下发模板信息");
                        /************************命令、模板相关******************************************************************/

                        /************************时间表相关******************************************************************/
                        //时间表
                        Dictionary<string, Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>>> timesTables = DbUtil.GetTimesTable(dbConnection, out Dictionary<string, Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>>> programTimesTables);
                        if (timesTables != null && timesTables.Count > 0)
                        {
                            //应该用hash的，这里懒得改了
                            redis.StringSet("stationTimesTables", timesTables);
                        }
                        mLogger.LogInformation("更新台站频率匹配时间表数据");
                        /************************时间表相关******************************************************************/

                        /************************调频、中波提前开机、延时关机数据初始化******************************************************************/
                        Dictionary<string, Dictionary<string, Dictionary<string, string>>> timeAdvanceAndDelayInfo = DbUtil.GetTimeAdvanceAndDelayInfo(dbConnection);
                        if (timeAdvanceAndDelayInfo != null && timeAdvanceAndDelayInfo.Count > 0)
                        {
                            foreach (string stationId in timeAdvanceAndDelayInfo.Keys)
                            {
                                redis.HashSet("timeAdvanceAndDelayInfo", stationId, timeAdvanceAndDelayInfo[stationId]);
                            }
                        }
                        mLogger.LogInformation("1~3级台站调频、中波提前开机、延时关机数据初始化");
                        /************************调频、中波提前开机、延时关机数据初始化******************************************************************/

                        /************************更新工位信息******************************************************************/
                        //台站级别 工位编号匹配信息
                        Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> workMatchNo = DbUtil.GetPositionInfoMatchNo(dbConnection);
                        //Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> workMatchNo = DbUtil.GetPositionInfoMatchNo(dbConnectionTmp);
                        if (workMatchNo != null && workMatchNo.Count > 0)
                        {
                            bool normal = true;
                            foreach (string key in workMatchNo.Keys)
                            {
                                if (workMatchNo[key] == null && workMatchNo[key].Count == 0)
                                {
                                    normal = false;
                                }
                            }
                            if (normal)
                            {
                                redis.StringSet("workMatchs", workMatchNo);
                            }
                        }

                        Dictionary<string, Dictionary<string, string>> workMatchNoSpec = DbUtil.GetPositionInfoMatchNoSpec(dbConnection);
                        if (workMatchNoSpec != null && workMatchNoSpec.Count > 0)
                        {
                            redis.StringSet("workMatchNoSpec", workMatchNoSpec);
                        }
                        mLogger.LogInformation("更新工位信息");

                                                //更新工位号信息，设备上报的+数据配置的，全部写入positionIds
                        Dictionary<string, string> positionIds = DbUtil.GetNodePositonids(dbConnection);
                        List<string> tmpPositionIds = redis.HashKeys<string>("station_deviceInfos");
                        if (tmpPositionIds != null && tmpPositionIds.Count > 0)
                        {
                            foreach (string positionId in tmpPositionIds)
                            {
                                if (!positionIds.ContainsKey(positionId))
                                {
                                    positionIds.TryAdd(positionId, "");
                                }
                            }
                        }
                        redis.StringSet("positionIds", positionIds.Keys.ToList());
                        mLogger.LogInformation("更新工位号信息");
                        /************************更新工位信息******************************************************************/

                        /************************历史数据存储******************************************************************/
                        //工位号数据自动初始化到历史存储主表
                        if (tmpPositionIds != null && tmpPositionIds.Count > 0)
                        {
                            foreach (string positionId in tmpPositionIds)
                            {
                                if (positionIds.ContainsKey(positionId))
                                { 
                                    string sql = "insert into his_set_main(position_id, dev_type, memo) select '{0}','{1}','{2}' where not exists(select 1 from his_set_main where position_id = '{3}')";
                                    DbUtil.ExecSql(dbConnection, sql, positionId, positionId.Split("_")[1], "系统自动新增", positionId);
                                }
                            }
                        }
                        mLogger.LogInformation("历史数据存储主表初始化");

                        Dictionary<string, Dictionary<string, string>> hisSetMainInfos = DbUtil.GetHisDataInfo(dbConnection);
                        if (hisSetMainInfos != null)
                        {
                            redis.StringSetAsync("hisSetMain", hisSetMainInfos);
                        }

                        Dictionary<string, List<Dictionary<string, string>>> hisDetailInfo = DbUtil.GetHisDetailInfo(dbConnection);
                        if (hisDetailInfo != null)
                        {
                            foreach (var devType in hisDetailInfo.Keys)
                            {
                                redis.HashSetAsync("hisSetDetail", devType, hisDetailInfo[devType]);
                            }
                            //移除无用的key
                            List<string> existsKeys = redis.HashKeys<string>("hisSetDetail");
                            List<string> delKeys = existsKeys.Where(l => !hisDetailInfo.ContainsKey(l)).ToList();
                            foreach (string key in delKeys)
                            {
                                redis.HashDeleteAsync("hisSetDetail", key);
                            }
                        }

                        mLogger.LogInformation("历史数据存储信息写如缓存");
                        /************************历史数据存储******************************************************************/

                        /************************更新设备信息******************************************************************/
                        //redis缓存的所有工位号keys
                        Dictionary<string, DeviceInfo> RedisDeviceInfos = redis.HashGetAllDict<DeviceInfo>("station_deviceInfos");
                        //数据库缓存的keys
                        Dictionary<string, Dictionary<string, string>> dbDeviceInfos = DbUtil.GetDeviceInfo(dbConnection);

                        if (RedisDeviceInfos != null)
                        {
                            foreach (DeviceInfo deviceInfo in RedisDeviceInfos.Values)
                            {
                                //地址端口组成KEY
                                if (dbDeviceInfos == null || !dbDeviceInfos.ContainsKey(deviceInfo.position_id))
                                {
                                    string insSql = "insert into device_info(serial_no,station_id,station_level,position_id,device_type,ip_addr,ip_type,port,dev_addr) " +
                                        " values(" +
                                        " '" + (deviceInfo.seviceSN ?? "") + "'," +
                                        " '" + (deviceInfo.stationCode ?? "") + "'," +
                                        " '" + (deviceInfo.staionLevel ?? "") + "'," +
                                        " '" + (deviceInfo.position_id ?? "") + "'," +
                                        " '" + (deviceInfo.deviceType ?? "") + "'," +
                                        " '" + (deviceInfo.ip_addr ?? "") + "'," +
                                        " '" + (deviceInfo.ip_type ?? "") + "'," +
                                        " '" + deviceInfo.port + "'," +
                                        " '" + (deviceInfo.dev_addr ?? "") + "'" +
                                        " )";
                                    DbUtil.ExecSql(dbConnection, insSql);
                                }

                                //端口或者设备地址有变化的，更新到device_info表
                                if (dbDeviceInfos != null && dbDeviceInfos.ContainsKey(deviceInfo.position_id) &&
                                    (
                                        !deviceInfo.port.ToString().Equals(dbDeviceInfos[deviceInfo.position_id]["port"]) ||
                                        !deviceInfo.dev_addr.Equals(dbDeviceInfos[deviceInfo.position_id]["dev_addr"]) ||
                                        !deviceInfo.ip_addr.Equals(dbDeviceInfos[deviceInfo.position_id]["ip_addr"]) ||
                                        !deviceInfo.seviceSN.Equals(dbDeviceInfos[deviceInfo.position_id]["serial_no"])
                                    )
                                )
                                {
                                    string id = dbDeviceInfos[deviceInfo.position_id]["id"];
                                    string updSql = "update device_info set serial_no='" + deviceInfo.seviceSN + "', port='" + deviceInfo.port + "', dev_addr='" + deviceInfo.dev_addr + "', ip_addr = '" + deviceInfo.ip_addr + "', get_time=now()  where id = " + id;
                                    DbUtil.ExecSql(dbConnection, updSql);
                                }
                            }
                            mLogger.LogInformation("同步设备信息到数据库");
                        }

                        RedisDeviceInfos = redis.HashGetAllDict<DeviceInfo>("station_deviceInfos");
                        Dictionary<string, Dictionary<string, DeviceInfo>> stationPositionDeviceInfos = new Dictionary<string, Dictionary<string, DeviceInfo>>();
                        foreach (string position_id in RedisDeviceInfos.Keys)
                        {
                            string stationCode = RedisDeviceInfos[position_id].stationCode;
                            if (!stationPositionDeviceInfos.ContainsKey(stationCode))
                            {
                                stationPositionDeviceInfos.TryAdd(stationCode, new Dictionary<string, DeviceInfo>());
                            }
                            stationPositionDeviceInfos[stationCode].TryAdd(position_id, RedisDeviceInfos[position_id]);
                        }
                        foreach (string stationId in stationPositionDeviceInfos.Keys)
                        {
                            batch.MHashSetAsync("station_position_deviceInfos", stationId, JsonConvert.SerializeObject(stationPositionDeviceInfos[stationId]));
                        }
                        batch.Execute();

                        //更新设置命令表
                        DbUtil.ExecSql(dbConnection, "insert into cmd_set(dev_id, set_id, memo) select a.id, b.id, '系统自动新增' from device_info a, dev_param_set b where a.device_type = b.device_type and not exists(select from cmd_set c where c.dev_id = a.id and c.set_id = b.id)");
                        DbUtil.ExecSql(dbConnection, "update cmd_set set is_used = true where set_id in(select id from dev_param_set)");
                        DbUtil.ExecSql(dbConnection, "update cmd_set set is_used = false where set_id not in(select id from dev_param_set)");
                        mLogger.LogInformation("更新设置命令表");

                        Dictionary<string, Dictionary<string, string>> cmdSetInfo = DbUtil.GetCmdSetInfo(dbConnection);
                        if (cmdSetInfo != null)
                        {
                            foreach (var key in cmdSetInfo.Keys)
                            {
                                redis.HashSetAsync("cmdSetInfo", key, cmdSetInfo[key]);
                            }
                            //移除无用的key
                            List<string> existsKeys = redis.HashKeys<string>("cmdSetInfo");
                            List<string> delKeys = existsKeys.Where(l => !cmdSetInfo.ContainsKey(l)).ToList();
                            foreach (string key in delKeys)
                            {
                                redis.HashDeleteAsync("cmdSetInfo", key);
                            }
                        }
                        /************************更新设备信息******************************************************************/

                        /************************告警历史表******************************************************************/
                        //按月分表
                        List<string> dmMonthAlarmHis = new List<string>
                        {
                            //当月
                            TransForm.GetFormatDatetime("yyyyMM"),
                            //下月
                            TransForm.DateTimeFormat(DateTime.Now.AddMonths(1), "yyyyMM")
                        };

                        string createTableSql = "";
                        foreach (string ym in dmMonthAlarmHis)
                        {
                            string tableName = "alarm_his_" + ym;

                            if (CheckTableExists(tableName))
                            {
                                continue;
                            }

                            createTableSql = "id int NOT NULL GENERATED ALWAYS AS IDENTITY (INCREMENT 1 MINVALUE  1 MAXVALUE 2147483647 START 1)";
                            foreach (string colName in CommonUtil.mAlarmHisColsDM.Keys)
                            {
                                createTableSql += "," + colName + " " + CommonUtil.mAlarmHisColsDM[colName];
                            }

                            createTableSql = "CREATE TABLE IF NOT EXISTS " + tableName + "(" + createTableSql + ")";
                            DbUtil.ExecSql(dbConnection, createTableSql);

                            //主键
                            string keySql = "ALTER TABLE " + tableName + " ADD CONSTRAINT " + tableName + "_pkey PRIMARY KEY (id)";
                            DbUtil.ExecSql(dbConnection, keySql);

                            string idxSql = "create index if not exists idx_station_id_" + ym + " on " + tableName + "(station_id)";
                            DbUtil.ExecSql(dbConnection, idxSql);

                            idxSql = "create index if not exists idx_sub_system_id_" + ym + " on " + tableName + "(sub_system_id)";
                            DbUtil.ExecSql(dbConnection, idxSql);

                            idxSql = "create index if not exists idx_device_type_" + ym + " on " + tableName + "(device_type)";
                            DbUtil.ExecSql(dbConnection, idxSql);

                            idxSql = "create index if not exists idx_alarm_id_" + ym + " on " + tableName + "(alarm_id)";
                            DbUtil.ExecSql(dbConnection, idxSql);

                            idxSql = "create index if not exists idx_frequency_" + ym + " on " + tableName + "(frequency)";
                            DbUtil.ExecSql(dbConnection, idxSql);

                            idxSql = "create index if not exists idx_ts_" + ym + " on " + tableName + "(ts)";
                            DbUtil.ExecSql(dbConnection, idxSql);
                        }
                        mLogger.LogInformation("告警历史表检查并创建");
                        /************************告警历史表******************************************************************/

                        /************************默认配置项增加******************************************************************/
                        //string paramSql = "insert into param_info(id, param_name, param_value, memo) select (select max(id)+1 from param_info), 'stationIdGlobal', '9999', '台站自身编码，全局变量' where not exists(select 1 from param_info where param_name = 'stationIdGlobal')";
                        //DbUtil.ExecSql(dbConnection, paramSql);
                        //paramSql = "insert into param_info(id, param_name, param_value, memo) select (select max(id)+1 from param_info), 'ReceiveDataUrl', 'ws://receive/data/1.0/1/0000_svrrcv_1/0', '数据采集服务url' where not exists(select 1 from param_info where param_name = 'ReceiveDataUrl')";
                        paramSql = "insert into param_info(id, param_name, param_value, memo) select (select max(id)+1 from param_info), 'ReceiveDataUrl', 'ws://192.168.0.110:30801/data/1.0/1/0000_svrrcv_1/0', '数据采集服务url' where not exists(select 1 from param_info where param_name = 'ReceiveDataUrl')";
                        DbUtil.ExecSql(dbConnection, paramSql);
                        paramSql = "insert into param_info(id, param_name, param_value, memo) select (select max(id)+1 from param_info), 'WebReceiveDataUrl', 'ws://webreceive/data/1.0/1/0000_svrwebrcv_1/0', 'web数据采集服务url' where not exists(select 1 from param_info where param_name = 'WebReceiveDataUrl')";
                        DbUtil.ExecSql(dbConnection, paramSql);
                        /************************默认配置项增加******************************************************************/
                    }
                }
                catch (Exception e)
                {
                    mLogger.LogError("更新配置出错啦，" + e);
                }
                finally
                {
                    mLogger.LogInformation("初始化完成");
                }

                //时间间隔
                //Thread.Sleep(10 * 60 * 1000);
                //Thread.Sleep(5 * 60 * 1000);
                Thread.Sleep(2 * 60 * 1000);
            }
        }

        /// <summary>
        /// 判断表是否存在
        /// </summary>
        /// <param name="tableName"></param>
        /// <returns></returns>
        private bool CheckTableExists(string tableName)
        {
            return bool.Parse(DbUtil.GetExecValue(dbConnection, "SELECT EXISTS(SELECT FROM information_schema.tables WHERE table_schema='public' AND table_name='{0}')", tableName));
        }

        /// <summary>
        /// 启动任务
        /// </summary>
        /// <param name="stoppingToken"></param>
        /// <returns></returns>
        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            mLogger.LogInformation("服务已启动！");

            new Thread(TimerInit).Start();
            new Thread(DealData).Start();   //数据处理线程
            return Task.CompletedTask;
        }
    }
}
